import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:io' show HttpStatus;

// import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:zhibao_flutter/api/user/user_view_model.dart';
import 'package:zhibao_flutter/util/check/check.dart';
import 'package:zhibao_flutter/util/config/app_config.dart';
import 'package:zhibao_flutter/util/func/log.dart';
import 'package:zhibao_flutter/util/func/tips_util.dart';
import 'package:zhibao_flutter/util/http/http.dart';
import 'package:zhibao_flutter/zone.dart';

final _client = HttpClient();

var _id = 0;

@netRequest
Future<dynamic> api(String url, ReqType reqType, bool retJson,
    [final obj,
    Duration? cacheTime,
    ProgressCallback? onReceiveProgress,
    ProgressCallback? onSendProgress]) async {
  // var connectivityResult = (Connectivity().checkConnectivity());
  // if (await connectivityResult == ConnectivityResult.none) {
  //   debugPrint(url);
  //   throw ResponseModel.fromParamError('请连接网络后再试');
  // }

  final id = _id++;
  final isHttp = url.startsWith('https://') || url.startsWith('http://');
  final _url =
      reqType == ReqType.html || isHttp ? url : '${Environment.current}$url';
  final httpUrl = _url + (isHttp ? '' : ''); //?tid=$tid
  Map? requestBody;
  StringBuffer? query;

  AnHttpResponse? response;

  if (reqType == ReqType.post) {
    requestBody = getKeys(obj);

    try {
      response = await _client.post(httpUrl, body: requestBody);
    } catch (e) {
      return netError(url, e, requestBody);
    }
  } else if (reqType == ReqType.patch) {
    requestBody = getKeys(obj);

    try {
      response = await _client.patch(httpUrl, body: requestBody);
    } catch (e) {
      return netError(url, e, requestBody);
    }
  } else if (reqType == ReqType.get || reqType == ReqType.html) {
    requestBody = getKeys(obj);

    try {
      response = await _client.get(httpUrl, body: requestBody);
    } catch (e) {
      return netError(url, e, requestBody);
    }
  } else if (reqType == ReqType.put) {
    requestBody = getKeys(obj);

    try {
      response = await _client.put(httpUrl, body: requestBody);
    } catch (e) {
      return netError(url, e, requestBody);
    }
  } else if (reqType == ReqType.del) {
    requestBody = getKeys(obj);
    try {
      response = await _client.del(httpUrl, body: requestBody);
    } catch (e) {
      return netError(url, e, requestBody);
    }
  } else if (reqType == ReqType.file) {
    requestBody = Map.from(obj.toJson());
    try {
      response = await _client.file(
        httpUrl,
        body: requestBody,
        onReceiveProgress: onReceiveProgress,
        onSendProgress: onSendProgress,
      );
    } catch (e) {
      return netError(url, e, requestBody);
    }
  } else {
    query = StringBuffer(url.contains("?s=") ? "&" : '?');

    if (obj is BaseRequest) {
      final map = jsonDecode(jsonEncode(obj));
      map.forEach((k, v) {
        if (v == null || v == 'null' || k == 'isFirstPage') return;

        query!
          ..write(k)
          ..write('=')
          ..write(v)
          ..write('&');
      });
    } else if (query != null) {
      query.write(obj);
    }

    try {
      response = await _client.getPin('$httpUrl$query');
    } catch (e) {
      return netError(url, e, requestBody);
    }
  }
  final statusCode = response?.code;

  switch (statusCode) {
    case HttpStatus.ok:
      final body = response!.body;
      if (reqType == ReqType.file) {
        debugPrint('HTTP_REQUEST_URL::[$id]::$httpUrl');
        LogUtil.d('HTTP_RESPONSE_BODY::[$id]::$body');
      } else {
        logPrint(reqType, query, id, httpUrl, requestBody, body);
      }

      if (reqType == ReqType.html) {
        return body;
      } else if (retJson) {
        final json = jsonDecode(body!);

        final result = json;
        return result;
      } else {
        logPrint(reqType, query, id, httpUrl, requestBody, body);
        return body;
      }
    case 429:
      throw ResponseModel.fromParamError(
          '错误');
    case 705:
      throw ResponseModel.fromParamError(
          '错误');
    case 500:
      throw ResponseModel.fromParamError(AppConfig.timeOutStr);
    case 404:
      throw ResponseModel.fromParamError(AppConfig.timeOutStr);
    case 403:
      throw ResponseModel.fromParamError(AppConfig.timeOutStr);
    case 401:
      if (Q1Data.isLogin) {
        userViewModel.loginOut();
      // return loginViewModel.tokenRefresh(null).then((value) {
      //   return api(url, reqType, retJson, obj, cacheTime, onReceiveProgress,
      //       onSendProgress, ossModel);
      // }).catchError(onError);
      }
      throw ResponseModel.fromParamError(AppConfig.loginExpired);
    case 405:
      throw ResponseModel.fromParamError(AppConfig.timeOutStr);
    case 502:
      throw ResponseModel.fromParamError(AppConfig.timeOutStr);
    default:
      var msg = strNoEmpty(response!.body)
          ? response.body
          : TipsUtil.netError;
      return {'Code': statusCode, 'Message': msg, 'Data': url};
  }
}

class HttpClient {
  Future<AnHttpResponse> get(url, {body}) async {
    final response = await Http.doGet(url, body);
    return response;
  }

  Future<AnHttpResponse> post(url, {body}) async {
    final response = await Http.doPost(url, body);
    return response;
  }

  Future<AnHttpResponse> patch(url, {body}) async {
    final response = await Http.doPatch(url, body);
    return response;
  }

  Future<AnHttpResponse?> file(
    url, {
    body,
    ProgressCallback? onReceiveProgress,
    ProgressCallback? onSendProgress,
  }) async {
    final response =
        await Http.doFile(url, body, onReceiveProgress, onSendProgress);
    return response;
  }

  Future<AnHttpResponse?> put(url, {body}) async {
    final response = await Http.doPut(url, body);
    return response;
  }

  Future<AnHttpResponse?> del(url, {body}) async {
    final response = await Http.doDel(url, body);
    return response;
  }

  Future<AnHttpResponse?> getPin(url) async {
    final response = await Http.doGetPin(Uri.encodeFull(url));
    return response;
  }
}

const _NetRequest netRequest = _NetRequest();

class _NetRequest {
  const _NetRequest();
}
